<template>
    <div ref="img" class="avatar flex-center" :class="{ round: props.round }">
        <n-image
            v-if="!defaultShown"
            :src="props.src"
            :lazy="props.lazy"
            :object-fit="props.objectFit"
            :preview-disabled="!props.preview"
            :img-props="{ onerror: onLoadFail }"
        />
        <n-image
            v-if="defaultShown"
            :preview-disabled="true"
            :src="props.fallbackSrc"
            :object-fit="props.objectFit"
        >
        </n-image>
        <!--        <img-->
        <!--            v-if="!defaultShown"-->
        <!--            :style="{ objectFit: objectFit }"-->
        <!--            :loading="props.lazyLoad ? 'lazy' : 'eager'"-->
        <!--            :src="props.src"-->
        <!--            @error="onLoadFail()"-->
        <!--        />-->

        <!-- src无效的时候显示默认头像 -->
        <!--        <img-->
        <!--            v-if="defaultShown"-->
        <!--            :style="{ objectFit: objectFit }"-->
        <!--            :src="props.defaultImg"-->
        <!--        />-->
        <template v-if="props.upload">
            <div
                v-if="props.upload && !uploading"
                class="overlay flex flex-center"
                @click="toUpload"
            >
                <jb-icon icon="ep:upload-filled" class="text-30px text-white"></jb-icon>
            </div>
            <div v-if="uploading" class="overlay active flex flex-center">
                <n-spin size="small"></n-spin>
            </div>
            <input
                ref="fileRef"
                type="file"
                class="hidden"
                :accept="props.accept"
                @change="onFileChoose($event)"
            />
        </template>
    </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { checkFileType } from '@/utils/common/file'
import { JBoltApi } from '@/utils/request'
import { UploadTo } from '@/typings/common'
import fallbackImgSrc from '@/assets/imgs/_builtin/default_avatar.png?url'
import { getServiceEnvConfig } from '~/.env-config'
interface Props {
    /** 图片地址*/
    src: string | undefined
    /** 是否显示为圆形 */
    round?: boolean
    width?: string | number
    height?: string | number
    /** 图片适应模式 */
    objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
    /** 是否懒加载，默认为true */
    lazy?: boolean
    /** 是否允许预览，开启上传时该属性将无效 */
    preview?: boolean
    /** 是否开启上传功能，默认不允许 */
    upload?: boolean
    /** 上传到哪里，暂时只提供上传到七牛和本地的功能 */
    uploadTo?: UploadTo
    /** 使用哪个七牛账号上传，不传则使用默认的，但需要后台配置默认账号 */
    qiniuSn?: string
    /** 保存地址，支持动态参数，参考 src/utils/common/file.ts中generatePath说明。默认值：avatar/{date(yyMMddHH)}/{random(5)}/{ori} */
    savePath?: string
    /** 上传接受的文件类型 */
    accept?: string
    /** 当未传入值或者图片无法访问时，要显示的图片地址 */
    fallbackSrc?: string
}

const props = withDefaults(defineProps<Props>(), {
    round: true,
    upload: false,
    width: 50,
    objectFit: 'cover',
    lazy: true,
    preview: true,
    qiniuSn: '',
    fallbackSrc: fallbackImgSrc,
    accept: 'image/jpg,image/png,image/gif,image/bmp,image/jpeg',
    savePath: 'avatar/{date(yyMMddHH)}/{random(5)}/{ori}'
})

const img = ref<HTMLElement | null>(null)

const uploadTo = computed(() => {
    const { defaultUploadTo } = getServiceEnvConfig(import.meta.env)
    return props.uploadTo || defaultUploadTo
})
const qiniuSn = computed(() => {
    const { defaultQiniuSn } = getServiceEnvConfig(import.meta.env)
    return props.qiniuSn || defaultQiniuSn
})
interface Emits {
    (e: 'update:src', value: string): void
}
const emits = defineEmits<Emits>()

/** 图片加载相关 start */

/**
 * src无效的时候显示默认图片
 */
const defaultShown = ref(!props.src)
watch(
    () => props.src,
    () => {
        defaultShown.value = !props.src
    }
)

function onLoadFail() {
    defaultShown.value = true
}
/** 图片加载相关 end */
/** 上传相关 start*/
const fileRef = ref<HTMLInputElement>()
const uploading = ref(false)
function toUpload() {
    console.debug('开始上传')
    fileRef.value?.click()
}

async function onFileChoose(event: Event) {
    const file = (event.target as HTMLInputElement)?.files?.[0]
    if (!file) {
        return
    }
    if (uploading.value) return
    if (checkFileType(file, props.accept) == false) {
        window.$error('文件类型不支持')
        return
    }
    uploading.value = true

    try {
        let path = null
        switch (uploadTo.value) {
            case 'qiniu':
                path = await JBoltApi.uploadToQiniu(
                    file,
                    props.savePath,
                    qiniuSn.value ?? ''
                )
                break
            case 'server':
                path = await JBoltApi.uploadToServer(file, props.savePath)
                break
            default:
                throw new Error('不支持的上传类型')
        }
        emits('update:src', path as string)
    } finally {
        uploading.value = false
    }
}
/** 上传相关 end*/

/** 尺寸相关 start */

const width = computed(() => {
    return isNaN(props.width as number) ? `${props.width}` : `${props.width}px`
})
const height = computed(() => {
    if (props.round) {
        return width.value
    } else if (props.height) {
        return isNaN(props.height as number) ? `${props.height}` : `${props.height}px`
    }
    return null
})

/** 尺寸相关 end */
</script>

<style scoped>
.avatar {
    position: relative;
    background: #f4f4f4;
    display: inline-flex;
    overflow: hidden;
    cursor: pointer;
}
.avatar.round {
    border-radius: 50%;
    aspect-ratio: 1;
}
.avatar :deep(.n-image img) {
    width: v-bind('width');
    height: v-bind('height');
}
.default_content {
    font-size: 100px;
}
.overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.1);
    transition: transform 0.3s;
    transform: scale(0);
    transform-origin: center;
}
.avatar:hover .overlay,
.overlay.active {
    display: flex;
    transform: scale(1);
}

.avatar img {
    width: 100%;
    height: 100%;
}
</style>
